package com.ken.apollo.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ken.apollo.commons.exception.ServiceException;
import com.ken.apollo.commons.utils.MailContentUtils;
import com.ken.apollo.domain.bo.MailBatchSendBo;
import com.ken.apollo.domain.entity.MailBatchSend;
import com.ken.apollo.domain.entity.MailSendDetail;
import com.ken.apollo.domain.entity.MailSenderConfig;
import com.ken.apollo.domain.query.MailBatchSendQuery;
import com.ken.apollo.domain.vo.MailBatchSendVo;
import com.ken.apollo.mapper.MailBatchSendMapper;
import com.ken.apollo.service.MailBatchSendService;
import com.ken.apollo.service.MailSendDetailService;
import com.ken.apollo.service.MailSenderConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import jakarta.mail.internet.MimeMessage;
import java.io.File;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Properties;
import java.util.stream.Collectors;

/**
 * 邮件群发记录表(MailBatchSend)表服务实现类
 *
 * @author Ken
 * @since 2025-08-25
 */
@Service
@Slf4j
public class MailBatchSendServiceImpl extends ServiceImpl<MailBatchSendMapper, MailBatchSend> implements MailBatchSendService {

    @Autowired
    private MailSendDetailService mailSendDetailService;

    @Autowired
    private MailSenderConfigService mailSenderConfigService;

    @Autowired
    private JavaMailSender javaMailSender;

    @Autowired
    @Qualifier("mailTaskExecutor")
    private ThreadPoolTaskExecutor mailTaskExecutor;

    @Value("${spring.mail.username}")
    private String defaultSenderEmail;
    
    @Value("${upload.path}")
    private String uploadPath;

    @Autowired
    private MailContentUtils mailContentUtils;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createBatchSendTask(MailBatchSendBo mailBatchSendBo) {
        log.info("【创建邮件群发任务】请求参数：{}", mailBatchSendBo);

        // 验证收件人数量
        if (ObjectUtil.isEmpty(mailBatchSendBo.getRecipients()) || mailBatchSendBo.getRecipients().size() > 100) {
            throw new ServiceException("收件人数量不能超过100个！");
        }

        // 创建群发任务
        MailBatchSend batchSend = new MailBatchSend();
        BeanUtil.copyProperties(mailBatchSendBo, batchSend);
        
        // 处理发送方配置
        if (mailBatchSendBo.getSenderConfigId() != null) {
            // 使用指定的发送方配置
            MailSenderConfig senderConfig = mailSenderConfigService.getById(mailBatchSendBo.getSenderConfigId());
            if (senderConfig == null || !senderConfig.getStatus()) {
                throw new ServiceException("指定的发送方配置不存在或已禁用！");
            }
            batchSend.setSenderEmail(senderConfig.getSenderEmail());
            if (StrUtil.isBlank(batchSend.getSenderName())) {
                batchSend.setSenderName(senderConfig.getSenderName());
            }
        } else {
            // 使用默认发送方配置
            MailSenderConfig defaultConfig = mailSenderConfigService.getDefaultConfig();
            if (defaultConfig != null) {
                batchSend.setSenderConfigId(defaultConfig.getId());
                batchSend.setSenderEmail(defaultConfig.getSenderEmail());
                if (StrUtil.isBlank(batchSend.getSenderName())) {
                    batchSend.setSenderName(defaultConfig.getSenderName());
                }
            } else {
                // 使用配置文件中的默认邮箱
                if (ObjectUtil.isEmpty(batchSend.getSenderEmail())) {
                    batchSend.setSenderEmail(defaultSenderEmail);
                }
            }
        }
        
        // 将收件人列表转换为JSON存储
        batchSend.setRecipients(JSONUtil.toJsonStr(mailBatchSendBo.getRecipients()));
        
        // 将附件列表转换为JSON存储
        if (ObjectUtil.isNotEmpty(mailBatchSendBo.getAttachments())) {
            batchSend.setAttachments(JSONUtil.toJsonStr(mailBatchSendBo.getAttachments()));
        }
        
        batchSend.setTotalCount(mailBatchSendBo.getRecipients().size());
        batchSend.setSuccessCount(0);
        batchSend.setFailedCount(0);
        batchSend.setStatus("pending");

        boolean result = this.save(batchSend);

        // 创建发送详情记录
        if (result) {
            List<MailSendDetail> details = mailBatchSendBo.getRecipients().stream().map(recipient -> {
                MailSendDetail detail = new MailSendDetail();
                detail.setBatchId(batchSend.getId());
                detail.setRecipientEmail(recipient.getEmail());
                detail.setRecipientName(recipient.getName());
                detail.setSendStatus("pending");
                return detail;
            }).collect(Collectors.toList());

            mailSendDetailService.saveBatch(details);
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean startBatchSend(Long batchId) {
        log.info("【开始执行群发任务】任务ID：{}", batchId);

        MailBatchSend batchSend = this.getById(batchId);
        if (ObjectUtil.isEmpty(batchSend)) {
            throw new ServiceException("群发任务不存在！");
        }

        if (!"pending".equals(batchSend.getStatus())) {
            throw new ServiceException("该任务已经执行过或正在执行中！");
        }

        // 更新任务状态为发送中
        batchSend.setStatus("sending");
        batchSend.setStartedAt(LocalDateTime.now());
        this.updateById(batchSend);

        // 异步执行邮件发送
        executeMailSendAsync(batchId);

        return true;
    }

    @Async("mailTaskExecutor")
    public void executeMailSendAsync(Long batchId) {
        log.info("【异步执行邮件群发】任务ID：{}, 线程：{}", batchId, Thread.currentThread().getName());

        MailBatchSend batchSend = this.getById(batchId);
        List<MailSendDetail> details = mailSendDetailService.getDetailsByBatchId(batchId);

        int successCount = 0;
        int failedCount = 0;

        for (MailSendDetail detail : details) {
            try {
                // 发送邮件
                sendSingleMail(batchSend, detail);
                
                // 更新发送状态为成功
                mailSendDetailService.updateSendStatus(detail.getId(), "success", null);
                successCount++;
                
                log.info("【邮件发送成功】收件人：{}", detail.getRecipientEmail());
                
                // 添加延迟避免频繁发送
                Thread.sleep(1000);
                
            } catch (Exception e) {
                log.error("【邮件发送失败】收件人：{}，错误信息：{}", detail.getRecipientEmail(), e.getMessage());
                
                // 更新发送状态为失败
                mailSendDetailService.updateSendStatus(detail.getId(), "failed", e.getMessage());
                failedCount++;
            }
        }

        // 更新群发任务最终状态
        batchSend.setSuccessCount(successCount);
        batchSend.setFailedCount(failedCount);
        batchSend.setStatus("completed");
        batchSend.setCompletedAt(LocalDateTime.now());
        this.updateById(batchSend);

        log.info("【邮件群发完成】任务ID：{}，成功：{}，失败：{}，线程：{}，线程池状态：{}", 
            batchId, successCount, failedCount, Thread.currentThread().getName(), getMailThreadPoolStatus());
    }
    
    @Async("mailTaskExecutor")
    public void executeRetryMailSendAsync(Long batchId) {
        log.info("【异步执行邮件重试】任务ID：{}, 线程：{}", batchId, Thread.currentThread().getName());

        MailBatchSend batchSend = this.getById(batchId);
        // 只获取失败的邮件详情
        List<MailSendDetail> failedDetails = mailSendDetailService.lambdaQuery()
                .eq(MailSendDetail::getBatchId, batchId)
                .eq(MailSendDetail::getSendStatus, "failed")
                .list();

        int retrySuccessCount = 0;
        int retryFailedCount = 0;

        log.info("【重试任务】开始重试失败邮件，失败邮件数量：{}", failedDetails.size());

        for (MailSendDetail detail : failedDetails) {
            try {
                // 发送邮件
                sendSingleMail(batchSend, detail);
                
                // 更新发送状态为成功
                mailSendDetailService.updateSendStatus(detail.getId(), "success", null);
                retrySuccessCount++;
                
                log.info("【重试邮件发送成功】收件人：{}", detail.getRecipientEmail());
                
                // 添加延迟避免频繁发送
                Thread.sleep(1000);
                
            } catch (Exception e) {
                log.error("【重试邮件发送失败】收件人：{}，错误信息：{}", detail.getRecipientEmail(), e.getMessage());
                
                // 更新错误信息，但保持failed状态
                mailSendDetailService.updateSendStatus(detail.getId(), "failed", "重试失败：" + e.getMessage());
                retryFailedCount++;
            }
        }

        // 更新群发任务最终状态
        int originalSuccessCount = batchSend.getSuccessCount() == null ? 0 : batchSend.getSuccessCount();
        int originalFailedCount = batchSend.getFailedCount() == null ? 0 : batchSend.getFailedCount();
        
        batchSend.setSuccessCount(originalSuccessCount + retrySuccessCount);
        batchSend.setFailedCount(originalFailedCount - retrySuccessCount); // 成功的邮件从失败数中减去
        batchSend.setStatus("completed");
        batchSend.setCompletedAt(LocalDateTime.now());
        this.updateById(batchSend);

        log.info("【邮件重试完成】任务ID：{}，重试成功：{}，重试失败：{}，线程：{}，线程池状态：{}", 
            batchId, retrySuccessCount, retryFailedCount, Thread.currentThread().getName(), getMailThreadPoolStatus());
    }

    /**
     * 发送单个邮件
     */
    private void sendSingleMail(MailBatchSend batchSend, MailSendDetail detail) throws Exception {
        // 获取发送方配置并创建对应的JavaMailSender
        JavaMailSender mailSender = getMailSenderByConfig(batchSend.getSenderConfigId());
        
        MimeMessage message = mailSender.createMimeMessage();
        
        // 检查是否有附件
        boolean hasAttachments = ObjectUtil.isNotEmpty(batchSend.getAttachments());
        
        // 根据是否有附件选择不同的处理方式
        MimeMessageHelper helper;
        if (hasAttachments) {
            // 有附件时使用multipart模式
            helper = new MimeMessageHelper(message, true, "UTF-8");
        } else {
            // 无附件时使用简单模式
            helper = new MimeMessageHelper(message, false, "UTF-8");
        }

        // 设置邮件基本信息
        helper.setFrom(batchSend.getSenderEmail(), batchSend.getSenderName());
        helper.setTo(detail.getRecipientEmail());
        helper.setSubject(batchSend.getSubject());
        
        // 处理邮件内容，将相对路径转换为绝对路径
        String processedContent = mailContentUtils.processMailContent(batchSend.getContent());
        
        // 设置HTML内容，使用处理后的内容
        helper.setText(processedContent, true);
        
        // 添加附件（只有在有附件时才处理）
        if (hasAttachments) {
            List<MailBatchSendBo.MailAttachment> attachments = JSONUtil.toList(
                batchSend.getAttachments(), MailBatchSendBo.MailAttachment.class);
            
            for (MailBatchSendBo.MailAttachment attachment : attachments) {
                try {
                    File attachmentFile = new File(uploadPath, attachment.getFilePath());
                    if (attachmentFile.exists() && attachmentFile.isFile()) {
                        FileSystemResource fileResource = new FileSystemResource(attachmentFile);
                        helper.addAttachment(attachment.getFileName(), fileResource);
                        log.debug("【添加附件成功】文件名：{}", attachment.getFileName());
                    } else {
                        log.warn("【附件不存在或不是文件】路径：{}", attachmentFile.getAbsolutePath());
                    }
                } catch (Exception e) {
                    log.error("【附件处理失败】文件名：{}, 错误：{}", attachment.getFileName(), e.getMessage());
                }
            }
        }

        // 发送邮件
        mailSender.send(message);
        
        // 更新发送时间
        detail.setSentAt(LocalDateTime.now());
        mailSendDetailService.updateById(detail);
        
        log.info("【HTML邮件发送成功】收件人：{}, 邮件主题：{}, 原始内容长度：{}, 处理后内容长度：{}, 附件数量：{}", 
            detail.getRecipientEmail(), batchSend.getSubject(), batchSend.getContent().length(), processedContent.length(),
            hasAttachments ? JSONUtil.toList(batchSend.getAttachments(), MailBatchSendBo.MailAttachment.class).size() : 0);
    }
    
    /**
     * 根据发送方配置获取JavaMailSender
     */
    private JavaMailSender getMailSenderByConfig(Long senderConfigId) {
        if (senderConfigId == null) {
            // 使用默认的JavaMailSender
            return javaMailSender;
        }
        
        MailSenderConfig config = mailSenderConfigService.getById(senderConfigId);
        if (config == null || !config.getStatus()) {
            log.warn("发送方配置不存在或已禁用，使用默认配置：{}", senderConfigId);
            return javaMailSender;
        }
        
        // 根据配置创建对应的JavaMailSender
        return createMailSender(config);
    }
    
    /**
     * 根据配置创建邮件发送器
     */
    private JavaMailSender createMailSender(MailSenderConfig config) {
        JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
        
        mailSender.setHost(config.getSmtpHost());
        mailSender.setPort(config.getSmtpPort());
        mailSender.setUsername(config.getSenderEmail());
        mailSender.setPassword(config.getSenderPassword());
        
        Properties props = mailSender.getJavaMailProperties();
        props.put("mail.transport.protocol", "smtp");
        props.put("mail.smtp.auth", config.getAuthEnable());
        props.put("mail.smtp.starttls.enable", config.getTlsEnable());
        props.put("mail.smtp.ssl.enable", config.getSslEnable());
        props.put("mail.debug", config.getDebugEnable());
        props.put("mail.smtp.connectiontimeout", config.getConnectionTimeout());
        props.put("mail.smtp.timeout", config.getReadTimeout());
        
        return mailSender;
    }

    @Override
    public List<MailBatchSendVo> listBatchSendTasks(MailBatchSendQuery query) {
        List<MailBatchSend> batchSends = this.lambdaQuery()
                .eq(ObjectUtil.isNotNull(query.getId()), MailBatchSend::getId, query.getId())
                .like(ObjectUtil.isNotEmpty(query.getBatchName()), MailBatchSend::getBatchName, query.getBatchName())
                .eq(ObjectUtil.isNotEmpty(query.getStatus()), MailBatchSend::getStatus, query.getStatus())
                .eq(ObjectUtil.isNotEmpty(query.getSenderEmail()), MailBatchSend::getSenderEmail, query.getSenderEmail())
                .orderByDesc(MailBatchSend::getCreateTime)
                .list();

        return batchSends.stream().map(this::convertToVo).collect(Collectors.toList());
    }

    @Override
    public MailBatchSendVo getBatchSendTaskById(Long id) {
        MailBatchSend batchSend = this.getById(id);
        if (ObjectUtil.isEmpty(batchSend)) {
            return null;
        }

        MailBatchSendVo vo = convertToVo(batchSend);
        
        // 查询发送详情
        List<MailSendDetail> details = mailSendDetailService.getDetailsByBatchId(id);
        vo.setSendDetails(details);

        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelBatchSend(Long batchId) {
        MailBatchSend batchSend = this.getById(batchId);
        if (ObjectUtil.isEmpty(batchSend)) {
            throw new ServiceException("群发任务不存在！");
        }

        if (!"pending".equals(batchSend.getStatus()) && !"sending".equals(batchSend.getStatus())) {
            throw new ServiceException("只能取消待发送或发送中的任务！");
        }

        batchSend.setStatus("cancelled");
        batchSend.setCompletedAt(LocalDateTime.now());
        return this.updateById(batchSend);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean retryBatchSend(Long batchId) {
        log.info("【重试群发任务】任务ID：{}", batchId);

        MailBatchSend batchSend = this.getById(batchId);
        if (ObjectUtil.isEmpty(batchSend)) {
            throw new ServiceException("群发任务不存在！");
        }

        // 只能重试已完成但有失败的任务
        if (!"completed".equals(batchSend.getStatus()) || batchSend.getFailedCount() == 0) {
            throw new ServiceException("只能重试已完成但有失败邮件的任务！");
        }

        // 限制重试次数
        int currentRetryCount = batchSend.getRetryCount() == null ? 0 : batchSend.getRetryCount();
        if (currentRetryCount >= 3) {
            throw new ServiceException("该任务已达到最大重试次数（3次）！");
        }

        // 更新任务状态为重试中
        batchSend.setStatus("retrying");
        batchSend.setRetryCount(currentRetryCount + 1);
        batchSend.setLastRetryTime(LocalDateTime.now());
        batchSend.setStartedAt(LocalDateTime.now());
        this.updateById(batchSend);

        // 异步执行重试邮件发送
        executeRetryMailSendAsync(batchId);

        return true;
    }

    /**
     * 转换为VO对象
     */
    private MailBatchSendVo convertToVo(MailBatchSend batchSend) {
        MailBatchSendVo vo = new MailBatchSendVo();
        BeanUtil.copyProperties(batchSend, vo);

        // 设置状态描述
        switch (batchSend.getStatus()) {
            case "pending":
                vo.setStatusDesc("等待发送");
                break;
            case "sending":
                vo.setStatusDesc("发送中");
                break;
            case "retrying":
                vo.setStatusDesc("重试中");
                break;
            case "completed":
                vo.setStatusDesc("已完成");
                break;
            case "cancelled":
                vo.setStatusDesc("已取消");
                break;
            case "failed":
                vo.setStatusDesc("发送失败");
                break;
            default:
                vo.setStatusDesc("未知状态");
        }

        // 计算进度百分比
        if (batchSend.getTotalCount() != null && batchSend.getTotalCount() > 0) {
            int processedCount = (batchSend.getSuccessCount() == null ? 0 : batchSend.getSuccessCount()) + 
                               (batchSend.getFailedCount() == null ? 0 : batchSend.getFailedCount());
            vo.setProgressPercent((double) processedCount / batchSend.getTotalCount() * 100);
        } else {
            vo.setProgressPercent(0.0);
        }

        return vo;
    }

    /**
     * 获取邮件线程池状态信息
     */
    public String getMailThreadPoolStatus() {
        if (mailTaskExecutor == null) {
            return "邮件线程池未初始化";
        }
        
        return String.format(
            "【邮件线程池状态】核心线程数：%d, 最大线程数：%d, 当前活跃线程数：%d, 当前线程池大小：%d, 任务队列大小：%d, 已完成任务数：%d",
            mailTaskExecutor.getCorePoolSize(),
            mailTaskExecutor.getMaxPoolSize(), 
            mailTaskExecutor.getActiveCount(),
            mailTaskExecutor.getPoolSize(),
            mailTaskExecutor.getQueueSize(),
            mailTaskExecutor.getThreadPoolExecutor().getCompletedTaskCount()
        );
    }
}